package com.yanqu.road.server.manger.bug;

import com.yanqu.road.dao.db.DbNameStrategy;
import com.yanqu.road.dao.db.DbParameter;
import com.yanqu.road.dao.impl.activity.operamask.OperaMaskSceneConfigDaoImpl;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.player.UserBagItem;
import com.yanqu.road.entity.player.UserInfo;
import com.yanqu.road.logic.bussiness.player.UserBagBussiness;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.player.BagModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;

import java.math.BigInteger;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ReduceGoodsMgr extends TempMgr {

    /**
     * 【批量扣道具】
     * <p>
     * 操作说明：
     * 1. 中心库t_s_reduce_goods如果不为空要先清空
     * 2. 在数据库中添加需要扣除的数据，resultStatus为0
     * 3. 后台的加载配置，加载ReduceGoodsMgr，就完成扣除了
     * 4. 中心库t_s_reduce_goods复制一份出来备份，检查下有没有漏扣除的（resultStatus为0表示未扣除）
     * 5. 用完后清空t_s_reduce_goods！！！
     * <p>
     * 数据库字段说明：
     * globalId             本次扣除的唯一ID，服务器会打印相应日志
     * userId               玩家ID
     * goods                需要扣除的道具，只能填t_u_bag里面有的，格式：110000=1;110001=2
     * multi                扣除倍数，正常填1，填几的话goods就会乘几
     * resultStatus         扣除状态，正常填0，0表示未执行，执行后会变为1
     * resultNoReduceGoods  扣除完毕后还有哪些道具没扣，空字符串表示全部扣除完毕
     * resultTime           扣除时间
     */
    public static void reduceGoods() {

        getLogger().error("执行扣道具");

        // long userIdMin = 10100028 * 10000000L + 1;
        long userIdMin = GameServer.getInstance().getServerId() * 10000000L + 1;
        long userIdMax = userIdMin + 10000000L - 2;

        OperaMaskSceneConfigDaoImpl dao = new OperaMaskSceneConfigDaoImpl();
        CallableStatement call = null;
        ResultSet rs = null;
        try {

            // 找需要扣的记录
            List<List<String>> dataList = new ArrayList<>();
            dao.getDb().setConnName(DbNameStrategy.getServerDb());
            call = dao.getDb().getConnection().prepareCall("SELECT * FROM t_s_reduce_goods WHERE userId >= ? AND userId <= ? AND resultStatus = 0");
            int i = 1;
            call.setLong(i++, userIdMin);
            call.setLong(i++, userIdMax);
            rs = call.executeQuery();
            while (rs.next()) {
                List<String> list = new ArrayList<>();
                list.add(rs.getLong("globalId") + "");
                list.add(rs.getLong("userId") + "");
                list.add(rs.getString("goods"));
                list.add(rs.getInt("multi") + "");
                dataList.add(list);
            }

            // 一个个扣
            for (List<String> list : dataList) {
                try {

                    // 准备参数
                    long globalId = Long.valueOf(list.get(0));
                    long userId = Long.valueOf(list.get(1));
                    String goods = list.get(2);
                    int multi = Integer.valueOf(list.get(3));
                    getLogger().error("[reduce goods handle] pre log : globalId {}, userId {}, goods {}, multi {}.", globalId, userId, goods, multi);

                    // 校验
                    UserInfo userInfo = UserMgr.getUserInfo(userId);
                    if (userInfo == null) {
                        continue;
                    }

                    // 需要扣除的道具
                    Property property = PropertyHelper.parseStringToProperty(goods);
                    property.rideProperty(multi);

                    // 还欠的道具
                    Property noReduceProp = new Property(property);

                    Object lock = GamePlayerMgr.getPlayerLock(userId);
                    synchronized (lock) {
                        GamePlayer onlinePlayer = GamePlayerMgr.getOnlinePlayer(userId);
                        if (onlinePlayer != null) {
                            // 在线玩家扣
                            BagModule bagModule = onlinePlayer.getModule(BagModule.class);
                            for (Map.Entry<Integer, BigInteger> entry : property.getGoods().entrySet()) {
                                int goodsId = entry.getKey();
                                long num = entry.getValue().longValue();

                                long haveNum = bagModule.getUserBagItemCount(goodsId);
                                long realReduceNum = Math.min(num, haveNum);
                                long leftNum = num - realReduceNum;

                                if (realReduceNum > 0) {
                                    String tmpStr = goodsId + "=" + realReduceNum;
                                    Property tmpProp = PropertyHelper.parseStringToProperty(tmpStr);
                                    if (onlinePlayer.getModule(CurrencyModule.class).removeCurrency(tmpProp, eLogMoneyType.GM, eLogMoneyType.GmDeductGoods)) {
                                        getLogger().error("[reduce goods handle] reduce : userId {}, goods {}.", userId, tmpStr);
                                        noReduceProp.setGood(goodsId, BigInteger.valueOf(leftNum));
                                    }
                                }
                            }
                            // 先拿的player锁再获取的玩家，玩家要移出内存就必须得先获得player锁再save才能移出
                            // synchronized (bagModule.getSaveLockObj()) {
                            //     bagModule.saveData();
                            // }

                        } else {
                            // 离线玩家扣
                            Map<Integer, UserBagItem> itemMap = UserBagBussiness.getUserBagItemMap(userId);
                            for (Map.Entry<Integer, BigInteger> entry : property.getGoods().entrySet()) {
                                int goodsId = entry.getKey();
                                long num = entry.getValue().longValue();

                                UserBagItem item = itemMap.get(goodsId);
                                if (item == null) {
                                    continue;
                                }
                                long haveNum = item.getNum();
                                long realReduceNum = Math.min(num, haveNum);
                                long leftNum = num - realReduceNum;

                                if (realReduceNum > 0) {
                                    item.setNum(item.getNum() - realReduceNum);
                                    if (UserBagBussiness.updateUserBagItem(item)) {
                                        String tmpStr = goodsId + "=" + realReduceNum;
                                        getLogger().error("[reduce goods handle] reduce : userId {}, goods {}.", userId, tmpStr);
                                        noReduceProp.setGood(goodsId, BigInteger.valueOf(leftNum));
                                        LogMgr.addLogGoods(goodsId, userId, false, realReduceNum, item.getNum(), eLogMoneyType.GmDeductGoods, userInfo.getVipExp());
                                    }
                                }
                            }
                        }
                    }

                    String tmpStr = PropertyHelper.parsePropertyToString(noReduceProp);

                    // 扣除结果
                    OperaMaskSceneConfigDaoImpl resultDao = new OperaMaskSceneConfigDaoImpl();
                    resultDao.getDb().setConnName(DbNameStrategy.getServerDb());
                    int resultI = 1;
                    Map<Integer, DbParameter> para = new HashMap<Integer, DbParameter>();
                    para.put(resultI++, new DbParameter(Types.INTEGER, 1));
                    para.put(resultI++, new DbParameter(Types.VARCHAR, tmpStr));
                    para.put(resultI++, new DbParameter(Types.TIMESTAMP, new Date()));
                    para.put(resultI++, new DbParameter(Types.BIGINT, globalId));
                    if (resultDao.getDb().executeNoneQuery("UPDATE t_s_reduce_goods SET resultStatus = ?, resultNoReduceGoods = ?, resultTime = ? WHERE globalId = ?", para) <= 0) {
                        getLogger().error("[reduce goods handle] finish error : globalId {}, resultNoReduceGoods {}.", globalId, tmpStr);
                    }

                } catch (Exception e) {
                    getLogger().error("error : ", e);
                }
            }


        } catch (Exception e) {
            getLogger().error("error : ", e);
        } finally {
            dao.getDb().closeConnection(call, rs);
        }
        getLogger().error("扣道具结束");

    }

    @Override
    public boolean init() throws Exception {
        return true;
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        reduceGoods();
        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }

}
